{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python 异常处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "'''\n",
    "\n",
    "\n",
    "异常处理\n",
    "捕捉异常可以使用try/except语句。\n",
    "\n",
    "try/except语句用来检测try语句块中的错误，从而让except语句捕获异常信息并处理。\n",
    "\n",
    "如果你不想在异常发生时结束你的程序，只需在try里捕获它。\n",
    "\n",
    "语法：\n",
    "\n",
    "以下为简单的try....except...else的语法：\n",
    "\n",
    "try:\n",
    "<语句>        #运行别的代码\n",
    "except <名字>：\n",
    "<语句>        #如果在try部份引发了'name'异常\n",
    "except <名字>，<数据>:\n",
    "<语句>        #如果引发了'name'异常，获得附加的数据\n",
    "else:\n",
    "<语句>        #如果没有异常发生\n",
    "\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# try的工作原理是\n",
    "\n",
    "\n",
    "'''\n",
    "\n",
    "try的工作原理是，当开始一个try语句后，python就在当前程序的上下文中作标记，这样当异常出现时就可以回到这里，try子句先执行，接下来会发生什么依赖于执行时是否出现异常。\n",
    "\n",
    "如果当try后的语句执行时发生异常，python就跳回到try并执行第一个匹配该异常的except子句，异常处理完毕，控制流就通过整个try语句（除非在处理异常时又引发新的异常）。\n",
    "如果在try后的语句里发生了异常，却没有匹配的except子句，异常将被递交到上层的try，或者到程序的最上层（这样将结束程序，并打印缺省的出错信息）。\n",
    "如果在try子句执行时没有发生异常，python将执行else语句后的语句（如果有else的话），然后控制流通过整个try语句。\n",
    "\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "文件不存在或者读取失败 或者没有权限\n"
     ]
    }
   ],
   "source": [
    "\n",
    "\n",
    "\n",
    "try:\n",
    "    fh = open('test_exccpt_file','r',encoding='UTF-8')\n",
    "   # fh = open('test_exccpt_file','w',encoding='UTF-8')\n",
    "    fh.write('一个用于测试异常的文件')\n",
    "    \n",
    "except IOError:\n",
    "    print('文件不存在 、或者读取失败 、或者没有权限')\n",
    "\n",
    "else :\n",
    "    print('内容写入成功')\n",
    "    fh.close()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "文件不存在 、或者读取失败 、或者没有权限\n"
     ]
    }
   ],
   "source": [
    "# 使用except而不带任何异常类型\n",
    "\n",
    "try:\n",
    "    fh = open('test_exccpt_file','r',encoding='UTF-8')\n",
    "   # fh = open('test_exccpt_file','w',encoding='UTF-8')\n",
    "    fh.write('一个用于测试异常的文件')\n",
    "    \n",
    "except:\n",
    "    print('文件不存在 、或者读取失败 、或者没有权限')\n",
    "\n",
    "else :\n",
    "    print('内容写入成功')\n",
    "    fh.close()\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 以上方式try-except语句捕获所有发生的异常。但这不是一个很好的方式，我们不能通过该程序识别出具体的异常信息。因为它捕获所有的异常。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用except而带多种异常类型\n",
    "\n",
    "'''\n",
    "\n",
    "try:\n",
    "    正常的操作\n",
    "   ......................\n",
    "except(Exception1[, Exception2[,...ExceptionN]]]):\n",
    "   发生以上多个异常中的一个，执行这块代码\n",
    "   ......................\n",
    "else:\n",
    "    如果没有异常执行这块代码\n",
    "\n",
    "\n",
    "'''\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### try-finally 语句"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# try-finally 语句无论是否发生异常都将执行最后的代码。\n",
    "\n",
    "'''\n",
    "\n",
    "try:\n",
    "<语句>\n",
    "finally:\n",
    "<语句>    #退出try时总会执行\n",
    "raise\n",
    "\n",
    "\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "文件不存在 、或者读取失败 、或者没有权限\n"
     ]
    },
    {
     "ename": "UnsupportedOperation",
     "evalue": "not writable",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mUnsupportedOperation\u001b[0m                      Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-11-eb09af061e2b>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      2\u001b[0m     \u001b[0mfh\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mopen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'test_exccpt_file'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;34m'r'\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mencoding\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m'UTF-8'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m     \u001b[1;31m# fh = open('test_exccpt_file','w',encoding='UTF-8')\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 4\u001b[1;33m     \u001b[0mfh\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwrite\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'一个用于测试异常的文件'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      5\u001b[0m \u001b[1;32mfinally\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      6\u001b[0m      \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'文件不存在 、或者读取失败 、或者没有权限'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mUnsupportedOperation\u001b[0m: not writable"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    fh = open('test_exccpt_file','r',encoding='UTF-8')\n",
    "    # fh = open('test_exccpt_file','w',encoding='UTF-8')\n",
    "    fh.write('一个用于测试异常的文件')\n",
    "finally:\n",
    "     print('文件不存在 、或者读取失败 、或者没有权限')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fh 文件关闭\n",
      "外层文件不存在 、或者读取失败 、或者没有权限\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    fh = open('test_exccpt_file','r',encoding='UTF-8')\n",
    "    try:\n",
    "         fh.write('一个用于测试异常的文件')\n",
    "    finally:\n",
    "        fh.close()\n",
    "        print('fh 文件关闭')\n",
    "except IOError:\n",
    "     print('外层文件不存在 、或者读取失败 、或者没有权限')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 异常的参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "'''\n",
    "\n",
    "异常的参数\n",
    "一个异常可以带上参数，可作为输出的异常信息参数。\n",
    "\n",
    "你可以通过except语句来捕获异常的参数，如下所示：\n",
    "\n",
    "try:\n",
    "    正常的操作\n",
    "   ......................\n",
    "except ExceptionType, Argument:\n",
    "    你可以在这输出 Argument 的值...\n",
    "变量接收的异常值通常包含在异常的语句中。在元组的表单中变量可以接收一个或者多个值。\n",
    "\n",
    "元组通常包含错误字符串，错误数字，错误位置。\n",
    "\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "参数没有包含数字 \n",
      " invalid literal for int() with base 10: 'adb'\n"
     ]
    }
   ],
   "source": [
    "def temp_convert(var):\n",
    "    try:\n",
    "        return int(var)\n",
    "    except ValueError as error:\n",
    "        print('参数没有包含数字 \\n',error)\n",
    "        \n",
    "temp_convert('adb')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 触发异常"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "'''\n",
    "触发异常\n",
    "我们可以使用raise语句自己触发异常\n",
    "\n",
    "raise语法格式如下：\n",
    "\n",
    "raise [Exception [, args [, traceback]]]\n",
    "语句中 Exception 是异常的类型（例如，NameError）参数标准异常中任一种，args 是自已提供的异常参数。\n",
    "\n",
    "最后一个参数是可选的（在实践中很少使用），如果存在，是跟踪异常对象。\n",
    "\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 ('Invalid leve1', 0)\n"
     ]
    }
   ],
   "source": [
    "def funcationName(leve1):\n",
    "    if leve1 < 1:\n",
    "        raise Exception('Invalid leve1',leve1)\n",
    "          # 触发异常后，后面的代码就不会再执行\n",
    "            \n",
    "            \n",
    "'''\n",
    "\n",
    "注意：为了能够捕获异常，\"except\"语句必须有用相同的异常来抛出类对象或者字符串。\n",
    "\n",
    "例如我们捕获以上异常，\"except\"语句如下所示：\n",
    "\n",
    "try:\n",
    "    正常逻辑\n",
    "except Exception,err:\n",
    "    触发自定义异常    \n",
    "else:\n",
    "    其余代码\n",
    "\n",
    "\n",
    "'''\n",
    "\n",
    "try:\n",
    "    funcationName(0)           \n",
    "except Exception as e:\n",
    "    print(1,e)\n",
    "else:\n",
    "    print(2)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 用户自定义异常"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('Bad hostname',)\n"
     ]
    }
   ],
   "source": [
    "'''\n",
    "\n",
    "通过创建一个新的异常类，程序可以命名它们自己的异常。异常应该是典型的继承自Exception类，通过直接或间接的方式。\n",
    "\n",
    "以下为与RuntimeError相关的实例,实例中创建了一个类，基类为RuntimeError，用于在异常触发时输出更多的信息。\n",
    "\n",
    "'''\n",
    "\n",
    "\n",
    "\n",
    "class NetWorkError(RuntimeError):\n",
    "    def _init_(self,arg):\n",
    "        self.args = arg\n",
    "\n",
    "\n",
    "\n",
    "try:\n",
    "    raise NetWorkError('Bad hostname')\n",
    "except NetWorkError as error:\n",
    "    print(error.args)\n",
    "    \n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
